package com.lc.admin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lc.admin.bean.LoginUserDetails;
import com.lc.admin.bean.User;
import com.lc.admin.constants.RedisKeyConstants;
import com.lc.admin.dto.LoginDto;
import com.lc.admin.mapper.UserMapper;
import com.lc.admin.service.UserService;
import com.lc.admin.utils.JwtUtil;
import com.lc.admin.vo.UserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Value("${zhyl.securet}")
    public String secret;

    @Value("${zhyl.expire}")
    public Integer expire;

    @Autowired
    @Lazy
    AuthenticationManager authenticationManager;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    UserMapper userMapper;

    @Autowired
    BCryptPasswordEncoder passwordEncoder;

    @Override
    public User getUserByUsername(String name) {
        return userMapper.getUserByUsername(name);
    }

    @Override
    public UserVo login(LoginDto loginDto) throws Exception {
        String encode = passwordEncoder.encode("123");
        System.out.println("123加密：" + encode);
        String name = Thread.currentThread().getName();
        System.out.println("service--Login()线程名：" + name);
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        if(!authenticate.isAuthenticated()) {
            throw new RuntimeException("登录失败");
        }
        // 组装一个UserVO类返回
        UserVo userVo = new UserVo();
        // 从Security上下文中取出用户基本信息
        LoginUserDetails loginUserDetails = (LoginUserDetails) authenticate.getPrincipal();


        // "roleLabels": null,
        Set<String> roleLabels = findLablesByUserId(loginUserDetails.getId());
        userVo.setRoleLabels(roleLabels);

        // "resourceRequestPaths": null,
        Set<String> resourceRequestPaths = findResourcesPathByUserId(loginUserDetails.getId());

        BeanUtils.copyProperties(loginUserDetails,userVo);
        userVo.setResourceRequestPaths(resourceRequestPaths);

        // 把用户信息封装成map集合
        Map<String,Object> claims = new HashMap<>();
        loginUserDetails.setResourceRequestPaths(resourceRequestPaths);
        claims.put("user", JSONObject.toJSONString(loginUserDetails));

        // 把token存储到redis中
        // token和redis中数据的生命周期需要一致
        String token = JwtUtil.createJWT(secret, expire, claims);
        String uuid = UUID.randomUUID().toString();

        redisTemplate.opsForValue().set(RedisKeyConstants.LOGIN_USER_UUID+loginUserDetails.getUsername(), uuid,expire, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(RedisKeyConstants.LOGIN_USER_TOKEN+uuid,token,expire,TimeUnit.SECONDS);
        userVo.setUserToken(uuid);

        return userVo;
    }

    @Override
    public Set<String> findLablesByUserId(Long id) {
        return userMapper.findLablesByUserId(id);
    }

    @Override
    public Set<String> findResourcesPathByUserId(Long id) {
        return userMapper.findResourcesPathByUserId(id);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String name = Thread.currentThread().getName();
        System.out.println("service--loadUserByUsername()线程名：" + name);
        User user = getUserByUsername(username);
        LoginUserDetails loginUserDetails = new LoginUserDetails();
        BeanUtils.copyProperties(user,loginUserDetails);
        return loginUserDetails;
    }
}
